﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Zen4SyncOrchestratorServices;
using Zen4SyncDashboard.DAL;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using Zen4SyncDashboard.DAL.Referential;
using System.Threading;

namespace Zen4SyncDashboard.ViewModel
{
    /// <summary>
    /// Represents the View Model exposing all Test Sessions for consultation.<br/>
    /// It refreshes the exposed Test Session on a timed basis.<br/>
    /// It allows starting a Test Session which is ready to be started.
    /// </summary>
    public class AllTestSessionsViewModel : BaseViewModel
    {
        #region - Fields -
        
        /// <summary>
        /// Used to communicate with the Orchestrator.
        /// </summary>
        ChannelFactory<IOrchestratorServices> orchestratorChannel;
        /// <summary>
        /// Used to refresh the exposed Test Sessions on a timed basis.
        /// </summary>
        Timer refreshTestSessionsTimer;

        #endregion - Fields -

        #region - Bound Properties -

        /// <summary>
        /// All the Test Session available, ordered by End Time (last ended come first).
        /// </summary>
        public ObservableCollection<testSession> TestSessions { get; private set; }
        /// <summary>
        /// Currently selected Test Session. Can be started if its status allows it.
        /// </summary>
        public testSession CurrentTestSession { get; set; }

        #endregion - Bound Properties -

        #region - Commands -

        public RelayCommand StartCurrentTestSessionCommand { get; private set; }

        #endregion - Commands -

        public AllTestSessionsViewModel()
        {
            InitializeFields();
            InitializeBoundProperties();
            InitializeCommands();
        }        

        #region - Initialization Methods -

        private void InitializeFields()
        {
            var ui = TaskScheduler.FromCurrentSynchronizationContext();

            Task.Factory.StartNew(
                () =>
                {
                    base.SetWorkStatus("Contacting Orchestrator...");
                    orchestratorChannel = new ChannelFactory<IOrchestratorServices>("Zen4SyncOrchestratorServices");

                    base.SetWorkStatus(false);
                })
                .ContinueWith( _ =>
                {
                    refreshTestSessionsTimer = new Timer(RefreshTestSessions, null, 5000, 3000);
                }
                , ui);
        }

        private void InitializeBoundProperties()
        {
            Task.Factory.StartNew(
                () =>
                {
                    base.SetWorkStatus("Fetching Test Sessions...");
                    TestSessions = Zen4SyncModel.TestSession.GetAllOrdered();
                    base.OnPropertyChanged("TestSessions");

                    base.SetWorkStatus(false);
                });
        }

        private void InitializeCommands()
        {
            StartCurrentTestSessionCommand = new RelayCommand(
                param => StartCurrentTestSession(),
                param => CanStartCurrentTestSession());
        }       

        #endregion - Initialization Methods -

        private void RefreshTestSessions(object state)
        {
            Task.Factory.StartNew(
                () =>
                {
                    base.SetWorkStatus("Refreshing Test Sessions...");
                    TestSessions = Zen4SyncModel.TestSession.GetAllOrdered();
                    base.OnPropertyChanged("TestSessions");

                    base.SetWorkStatus(false);
                });
        }

        private bool CanStartCurrentTestSession()
        {
            return CurrentTestSession != null
                && CurrentTestSession.testSessionState.testSessionState_id == GuidReferential.TestSessionState.Planned;
        }

        private void StartCurrentTestSession()
        {
            Guid sessionToStart = CurrentTestSession.testSession_id;
            string pw = "admin";

            orchestratorChannel.Call(
                orchestrator => orchestrator.StartTestSession(sessionToStart, pw));
        }
    }
}
